<template>
  <div class="dept-selector">
    <el-dialog
      v-model="dialogVisible"
      :title="selectLimit === 1 ? `选择${treeTitle}` : `选择${treeTitle}（多选）`"
      width="500px"
      @close="handleClose"
    >
      <div class="dept-tree-container">
        <div class="search-header">
          <el-input
            v-model="filterText"
            :placeholder="`搜索${treeTitle}`"
            clearable
            class="search-input"
          >
            <template #prefix>
              <el-icon><Search /></el-icon>
            </template>
          </el-input>
          <div class="selected-info">
            <span v-if="selectLimit > 0">已选择 {{ selectedDepts.size }}/{{ selectLimit }} 个{{ treeTitle }}</span>
            <span v-else>已选择 {{ selectedDepts.size }} 个{{ treeTitle }}</span>
          </div>
        </div>
        <div class="tree-wrapper">
          <!-- 添加加载状态 -->
          <div v-if="loading" class="loading-container">
            <el-skeleton animated />
          </div>
          <el-tree
            v-else
            ref="deptTreeRef"
            :data="effectiveDepartmentTree"
            :node-key="nodeKey"
            :props="deptProps"
            :filter-node-method="filterNode"
            :show-checkbox="selectLimit !== 1"
            :check-strictly="true"
            :default-checked-keys="defaultCheckedKeys"
            :default-expanded-keys="expandedKeys"
            :expand-on-click-node="selectLimit === 1"
            @check="handleCheckChange"
            @node-click="handleNodeClick"
          >
          <template #default="{ node, data }">
              <div class="custom-tree-node">
                <el-radio-group v-if="selectLimit === 1" v-model="radioSelected" @change="handleRadioChange">
                  <el-radio :value="data[nodeKey]" class="radio-node">
                    <span>{{ node.label }}</span>
                  </el-radio>
                </el-radio-group>
                <span v-else>{{ node.label }}</span>
              </div>
            </template>
          </el-tree>
        </div>
      </div>
      
      <template #footer>
        <div class="dialog-footer">
          <el-switch
            v-if="selectLimit !== 1"
            v-model="selectAllSwitch"
            active-text="全选"
            @change="handleSelectAllChange"
            class="select-all-switch"
          />
          <div class="spacer" v-else></div> <!-- 单选时添加占位符 -->
          <div class="footer-buttons">
            <el-button @click="handleClose">取消</el-button>
            <el-button type="primary" @click="handleConfirm" :disabled="isConfirmDisabled">确定</el-button>
          </div>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, computed, watch, nextTick, onMounted } from 'vue'
import { Search } from '@element-plus/icons-vue'

const emit = defineEmits(['confirm', 'cancel'])
// 定义 props
const props = defineProps({
  treeData: {
    type: Array,
    default: () => []
  },
  selected:{
    type: Array,
    default: () => []
  },
  // 添加 dataApi 属性，用于从后台获取数据
  dataApi: {
    type: String,
    default: ''
  },
  treeTitle : {
    type: String,
    default: '部门'
  },
  dataKey:{
    type: String,
    default: 'id'
  },
  onConfirm: Function,
  onCancel: Function,
  limit: {
    type: Number,
    default: 0 // 0表示无限制，其他值表示最多可选数量
  }, 
  visible: {
    type: Boolean,
    default: false
  }
})

// 组件引用
const deptTreeRef = ref()

// 数据状态
const nodeKey = ref(props.dataKey)
const dialogVisible = ref(props.visible)
const filterText = ref('')
const internalDepartmentTree = ref([]) // 内部部门树数据
const selectedDeptIds = ref([])
const selectedDepts = ref(new Map()) // 使用 Map 存储选中的部门信息
const currentCallback = ref(null)
const selectLimit = ref(props.limit) // 0表示无限制，1表示单选，>1表示限制选择个数
const expandedKeys = ref([])
const radioSelected = ref(null)
// 添加全选开关状态
const selectAllSwitch = ref(false)
// 添加加载状态
const loading = ref(false)

// 计算属性：优先使用传入的部门树数据，否则使用内部数据
const effectiveDepartmentTree = computed(() => {
  return props.treeData.length > 0 ? props.treeData : internalDepartmentTree.value
})

// 部门树配置
const deptProps = {
  children: 'children',
  label: 'name'
}

const defaultCheckedKeys = computed(() => {
  if (selectLimit.value === 1) {
    // 单选模式下不使用默认选中，因为使用了 radioSelected
    return []
  } else {
    // 多选模式下使用默认选中的键值
    return selectedDeptIds.value
  }
})

const handleRadioChange = (value) => {
  if (selectLimit.value === 1) {
    selectedDepts.value.clear()
    const dept = findDepartmentById(effectiveDepartmentTree.value, value)
    if (dept) {
      selectedDepts.value.set(dept[nodeKey.value], dept)
    }
  }
}

// 过滤节点
const filterNode = (value, data) => {
  if (!value) return true
  return data.name.includes(value)
}

// 监听搜索框变化
watch(filterText, (val) => {
  deptTreeRef.value.filter(val)
})

// 是否禁用确认按钮
const isConfirmDisabled = computed(() => {
  const selectedCount = selectedDepts.value.size
  return selectedCount === 0 || (selectLimit.value > 0 && selectedCount > selectLimit.value)
})

// 处理节点选中变化（多选）
const handleCheckChange = (data, { checkedKeys, checkedNodes }) => {
  // 如果有限制数量且当前选中数量达到或超过限制
  if (selectLimit.value > 0 && checkedNodes.length > selectLimit.value) {
    // 取消刚刚的选中操作
    deptTreeRef.value.setChecked(data, false)
    
    // 重新获取当前选中的节点
    const currentCheckedNodes = deptTreeRef.value.getCheckedNodes()
    checkedNodes = currentCheckedNodes
  }
  
  // 更新选中的部门
  selectedDepts.value.clear()
  checkedNodes.forEach(node => {
    selectedDepts.value.set(node[nodeKey.value], node)
  })
  
  // 更新全选开关状态
  updateSelectAllState()
  
  refreshTree()
}

const getAllTreeNodes = () => {
  const allNodes = []
  const traverse = (nodes) => {
    nodes.forEach(node => {
      allNodes.push(node)
      if (node.children && node.children.length > 0) {
        traverse(node.children)
      }
    })
  }
  traverse(effectiveDepartmentTree.value)
  return allNodes
}

const handleSelectAllChange = (checked) => {
  if (selectLimit.value === 1) return // 单选模式下不处理
  
  if (checked) {
    // 全选 - 但需要考虑限制数量
    const allNodes = getAllTreeNodes()
    
    if (selectLimit.value > 0 && allNodes.length > selectLimit.value) {
      // 如果全选会超过限制，则只选择前limit个节点
      const limitedNodes = allNodes.slice(0, selectLimit.value)
      selectedDepts.value.clear()
      limitedNodes.forEach(node => {
        selectedDepts.value.set(node[nodeKey.value], node)
      })
      selectAllSwitch.value = false // 由于不是真正全选，开关设为false
    } else {
      // 正常全选
      selectedDepts.value.clear()
      allNodes.forEach(node => {
        selectedDepts.value.set(node[nodeKey.value], node)
      })
    }
  } else {
    // 取消全选
    selectedDepts.value.clear()
  }
  
  refreshTree()
}

const updateSelectAllState = () => {
  if (selectLimit.value === 1) return // 单选模式下不处理
  
  const allNodes = getAllTreeNodes()
  const selectedKeys = Array.from(selectedDepts.value.keys())
  
  // 如果所有节点都被选中，则全选开关为true
  if (allNodes.length > 0 && selectedKeys.length === allNodes.length) {
    selectAllSwitch.value = true
  } else {
    selectAllSwitch.value = false
  }
}

// 处理节点点击（单选）
const handleNodeClick = (data) => {
  if (selectLimit.value === 1) {
    selectedDepts.value.clear()
    selectedDepts.value.set(data[nodeKey.value], data)
  }
}

// 关闭对话框
const handleClose = () => {
  dialogVisible.value = false
  selectedDepts.value.clear()
  selectedDeptIds.value = []
  filterText.value = ''
  if (props.onCancel && typeof props.onCancel === 'function') {
    props.onCancel()
  }
  emit('cancel')
}

// 确认选择
const handleConfirm = () => {
  const result = {
    ids: Array.from(selectedDepts.value.keys()),
    names: Array.from(selectedDepts.value.values()).map(dept => dept.name)
  }
  if (props.onConfirm && typeof props.onConfirm === 'function') {
    try {
      props.onConfirm(result)
    } catch (error) {
      console.error('onConfirm 回调执行出错:', error)
    }
  }
  emit('confirm', result)
  if (currentCallback.value) {
    currentCallback.value(result)
  }
  
  handleClose()
}

// 通过 URL 获取部门数据
const loadDepartmentData = async () => {
  // 如果有传入的 treeData 数据，优先使用
  if (props.treeData.length > 0) {
    return
  }
  
  // 如果有 dataApi，则通过 URL 获取数据
  if (props.dataApi) {
    try {
      loading.value = true
      const response = await fetch(props.dataApi)
      const data = await response.json()
      internalDepartmentTree.value = data || []
    } catch (error) {
      console.error('获取部门数据失败:', error)
      // 获取失败时使用默认数据
      loadMockData()
    } finally {
      loading.value = false
    }
  }
}

const selectedIdsToDepartments = (selectedIds = []) => { 
  // 限制选择数量
  if(selectLimit.value >= 1){
    selectedIds = selectedIds.slice(0, selectLimit.value)
  }
  selectedDeptIds.value = selectedIds
 
  selectedDepts.value.clear()
  radioSelected.value = null // 重置单选状态
  selectAllSwitch.value = false // 重置全选开关
  
  // 初始化选中的部门
  nextTick(async () => {
    // 加载部门数据
    await loadDepartmentData()
    
    selectedIds.forEach(id => {
      const dept = findDepartmentById(effectiveDepartmentTree.value, id)
      if (dept) {
        selectedDepts.value.set(dept[nodeKey.value], dept)
        // 设置单选选中的值
        if (selectLimit.value === 1 && selectedDepts.value.size === 1) {
          radioSelected.value = id
        }
      }
    })
    // 展开已选中的节点
    expandSelectedNodes()
    
    // 更新全选状态
    updateSelectAllState()
    
    // 强制刷新树组件
    refreshTree()
  })
}

// 修改 selectDept 方法，在初始化时更新全选状态
const selectTreeDialog = (selectedIds = [], callback, limitCount = 0) => {
  currentCallback.value = callback
  selectLimit.value = limitCount
  dialogVisible.value = true    
  selectedIdsToDepartments(selectedIds)  
}

// 强制刷新树组件
const refreshTree = () => {
  selectedDeptIds.value = Array.from(selectedDepts.value.keys())
  if (deptTreeRef.value) {
    deptTreeRef.value.setCheckedKeys([])
    if (selectLimit.value !== 1) {
      deptTreeRef.value.setCheckedKeys(selectedDeptIds.value)
    }
  }
}

// 根据ID查找部门
const findDepartmentById = (nodes, id) => {
  for (const node of nodes) {
    if (node[nodeKey.value] === id) {
      return node
    }
    if (node.children && node.children.length > 0) {
      const found = findDepartmentById(node.children, id)
      if (found) return found
    }
  }
  return null
}

// 展开已选中的节点
const expandSelectedNodes = () => {
  const keys = []
  const expandNode = (nodes) => {
    nodes.forEach(node => {
      if (selectedDepts.value.has(node[nodeKey.value]) && node.children && node.children.length > 0) {
        keys.push(node[nodeKey.value])
        expandNode(node.children)
      } else if (node.children && node.children.length > 0) {
        expandNode(node.children)
      }
    })
  }
  expandNode(effectiveDepartmentTree.value)
  expandedKeys.value = keys
}

// 模拟数据
const loadMockData = () => {
  // 模拟部门树数据
  internalDepartmentTree.value = [
    {
      id: 1,
      name: '总公司',
      children: [
        {
          id: 2,
          name: '技术部',
          children: [
            { id: 3, name: '前端组' },
            { id: 4, name: '后端组' }
          ]
        },
        {
          id: 5,
          name: '人事部'
        },
        {
          id: 6,
          name: '财务部'
        },
        {
          id: 7,
          name: '设计部'
        },
        {
          id: 8,
          name: '运维部'
        }
      ]
    }
  ]
}

onMounted(() => {
  loadDepartmentData()

  if (props.selected) {
    if (Array.isArray(props.selected)) {
      selectedIdsToDepartments(props.selected)
      return
    }
    selectedIdsToDepartments(props.selected.split(','))
  }
})

// 暴露方法给父组件
defineExpose({
  selectTreeDialog
})
</script>

<style scoped>
.dept-tree-container {
  height: 400px;
  display: flex;
  flex-direction: column;
}

.search-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
}

.search-input {
  flex: 1;
}
.loading-container {
  padding: 20px;
}
.tree-wrapper {
  flex: 1;
  overflow-y: auto;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  padding: 10px;
}

.selected-info {
  font-size: 12px;
  color: #666;
  white-space: nowrap;
}

.dialog-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 20px;
}

.select-all-switch {
  flex: 1;
}

.footer-buttons {
  display: flex;
  gap: 10px;
}

.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
}

.radio-node {
  margin-right: 0;
}

.radio-node :deep(.el-radio__label) {
  padding-left: 5px;
}
</style>